#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging
import argparse
import os
import sys
import time
import types
from ptext import *

class Peacemaker:
	
	def addMethod(self, func):
		return setattr(self, func.__name__, types.MethodType(func, self))
		
	def __init__(self):
		
		self.InitIdentity()
		
		self.InitCharacterClasses()
		
		self.InitLogging()
		
		self.Greet()
		
		self.InitModules()
		
		self.InitArgParse()
		
		self.InitIOFileResolution()
		
		self.LoadModules()
		
		return
	
	def Process(self):
		if self.init_input() != True:
			self.log.error("Failed to load "+self.module_input.cfg['name']+" input module!")
		if self.readfile() != True:
			self.log.error("Failed to load "+self.infilename+"!")
		
		if self.init_processing() != True:
			self.log.error("Failed to load "+self.module_language.cfg['name']+" language module!")
		if self.preprocess() != True:
			self.log.error("Language module "+self.module_language.cfg['name']+" preprocessing failed!")
		if self.process() != True:
			self.log.error("Language module "+self.module_language.cfg['name']+" processing failed!")
		if self.postprocess() != True:
			self.log.error("Language module "+self.module_language.cfg['name']+" postprocessing failed!")
		
		if self.init_output() != True:
			self.log.error("Failed to load '"+self.module_output.cfg['name']+"' output module!")
		if self.writefile() != True:
			self.log.error("Failed to save "+self.outfilename+"!")
			
		return
	
	def InitIdentity(self):
		
		self.name = "Pacify"
		self.renametoken = "pacified"
		self.version = "2011.10"
		self.copyrightdate = "2009"
		self.author = "AGGOTT HÖNSCH István"
		self.beginat = time.mktime(time.localtime())
		if int(time.strftime("%Y")) > 2009:
			self.copyrightdate += "-" + time.strftime("%Y", time.localtime())
		
		return True
	
	def LoadModules(self):
		for module in self.modules:
			if module['cfg']['type'] == 'language' and module['cfg']['name'] == self.languagecfg['name'] and module['cfg']['version'] == self.languagecfg['version']:
				module['src'].load_module(self)
			if module['cfg']['type'] == 'input' and module['cfg']['name'] == self.inputcfg['name'] and module['cfg']['version'] == self.inputcfg['version']:
				module['src'].load_module(self)
			if module['cfg']['type'] == 'output' and module['cfg']['name'] == self.outputcfg['name'] and module['cfg']['version'] == self.outputcfg['version']:
				module['src'].load_module(self)
		return True
	
	def InitModules(self):
		
		self.modules = []
		
		for filename in os.listdir("."):
			if filename[0:7].lower() == 'pacify_' and filename[-3:].lower() == '.py':
				tmpfile = open(filename, 'r')
				firstline = tmpfile.readline().strip()
				if firstline[:2] + firstline[-2:] == '#<>#':
					tmodule = {}
					tmodule['cfg'] = eval(firstline[3:-3])
					tmodule['src'] = __import__(filename[:-3])
					self.modules.append(tmodule)
				tmpfile.close()
		
		for module in self.modules:
			if module['cfg']['type'] == 'language': self.log.info("Found language module for "+module['cfg']['name']+".")
		
		for module in self.modules:
			if module['cfg']['type'] == 'input': self.log.info("Found input module for "+module['cfg']['name']+".")
		
		for module in self.modules:
			if module['cfg']['type'] == 'output': self.log.info("Found output module for "+module['cfg']['name']+".")
		
		self.log.debug(repr(self.modules).encode('utf-8', 'ignore'))
		
		print('')
		
		return True
	
	def InitIOFileResolution(self):
		
		# Resolves both filenames and input, output, and language formats based on file extensions and information provided via the command line
		
		self.infilename = ''
		self.outfilename = ''
		
		for module in self.modules:
			if module['cfg']['type'] == 'language' and module['cfg']['argvalue'] == self.args.l:
				self.languagecfg = module['cfg']
		
		if os.path.isfile(self.args.infilename):
			for module in self.modules:
				if module['cfg']['type'] == 'input' and module['cfg']['extension'] == self.args.infilename[self.args.infilename.rfind('.')+1:]:
					self.log.info('Input file format identified as: '+module['cfg']['name'])
					self.infilename = self.args.infilename
					self.inputcfg = module['cfg']
			if self.infilename == '':
				self.log.error("No input module found for '." + self.args.infilename[self.args.infilename.rfind('.')+1:] + "'.  Exiting.")
				sys.exit(1)
		else:
			self.log.error("Input file '" + self.args.infilename + "' not found.  Exiting.")
			sys.exit(1)
		
		if self.args.o != '':
			for module in self.modules:
				if module['cfg']['type'] == 'output' and module['cfg']['argvalue'] == self.args.o:
					self.outputcfg = module['cfg']
					self.log.info('Output file format identified as: '+module['cfg']['name'])
		else:
			if self.args.outfilename.rfind('.') > -1:
				for module in self.modules:
					if module['cfg']['type'] == 'output' and module['cfg']['extension'] == self.args.outfilename[self.args.outfilename.rfind('.')+1:]:
						self.log.info('Output file format identified as: '+module['cfg']['name'])
						self.outfilename = self.args.outfilename
						self.outputcfg = module['cfg']
				if self.outfilename == '':
					self.log.error("No output module found for '." + self.args.outfilename[self.args.outfilename.rfind('.')+1:] + "'.  Exiting.")
					sys.exit(1)
			else:
				self.log.error('No output format was specified or implied.  Exiting.')
				sys.exit(1)
		
		print('')
		
		if len(self.args.outfilename) == 0:
			self.outfilename = self.args.infilename[:self.args.infilename.rfind('.')]+'-'+self.renametoken+'.'+self.outputcfg['extension']
		
		self.log.info('Processing: '+self.infilename+' --> '+self.outfilename)
		self.log.info("Selected "+self.inputcfg['name']+" input module.")
		self.log.info("Selected "+self.languagecfg['name']+" language module.")
		self.log.info("Selected "+self.outputcfg['name']+" output module.")
		
		print('')
		
		if os.path.isfile(self.outfilename):
			if self.args.overwrite == True:
				answer = 'y'
			else:
				answer = input("Output file '" + self.outfilename + "' already exists.\nOverwrite? (Y/N) ")
				print('')
			if answer == 'y' or answer == 'Y':
				self.log.info("Output will overwrite '" + self.outfilename + "'.")
				print('')
			else:
				self.log.info("May not overwrite '" + self.outfilename + "'.  Exiting.")
				sys.exit(1)
		
		return True
	
	def InitArgParse(self):
		
		self.languagelist = []
		self.outputlist = []
		
		for module in self.modules:
			if module['cfg']['type'] == "language":
				self.languagelist.append(module['cfg']['argvalue'])
		
		for module in self.modules:
			if module['cfg']['type'] == "output":
				self.outputlist.append(module['cfg']['argvalue'])
		
		parser = argparse.ArgumentParser()
		parser.add_argument('infilename', metavar='input.ext')
		parser.add_argument('outfilename', metavar='output.ext', default='', nargs="?")
		parser.add_argument('-l', choices=self.languagelist, required=True, help="specify input content's language code")
		parser.add_argument('-o', choices=self.outputlist, default='', help="specify output format")
		parser.add_argument('--overwrite', action='store_true', help="automatically overwrite output file, if it already exists")
		
		self.args = parser.parse_args()
		
		return True
	
	def InitLogging(self):
		
		logging.basicConfig(	level=logging.DEBUG,
								filename="pacify.log",
								filemode="w",
								format="%(asctime)s; %(levelname)s; %(name)s; %(message)s")
		
		console = logging.StreamHandler()
		console.setLevel(logging.INFO)
		console.setFormatter(logging.Formatter('%(asctime)-23s - %(message)s'))
		logging.getLogger('').addHandler(console)
		
		self.log = logging
		
		return True
	
	def Greet(self):
		
		print("\n"+self.name + " v" + self.version + " - Copyright " + self.copyrightdate + " " + self.author + "\n")
		self.log.debug(self.name + " v" + self.version + " - Copyright " + self.copyrightdate + " " + self.author)
		self.log.debug("Python " + sys.version)
		
		return True
	
	def InitCharacterClasses(self):
		
		self.alphalower  = "aeiouy"
		self.alphalower += "áàăắằẵẳâấầẫẩǎåǻäǟãȧǡąāảȁȃạặậḁⱥᶏɐɑ"
		self.alphalower += "éèĕêếềễểěëẽėȩḝęēḗḕẻȅȇẹệḙḛɇᶒⱸ"
		self.alphalower += "íìĭîǐïḯĩįīỉȉȋịḭɨᵻᶖiı"
		self.alphalower += "óòŏôốồỗổǒöȫőõṍṏȭȯȱøǿǫǭōṓṑỏȍȏơớờỡởợọộɵⱺ"
		self.alphalower += "úùŭûǔůüǘǜǚǖűũṹųūṻủȕȗưứừữửựụṳṷṵʉᵾᶙ"
		self.alphalower += "ýỳŷẙÿỹẏȳỷỵɏƴ"
		
		self.alphalower += "bcdfghjklmnpqrstvwxz"
		self.alphalower += "ḃḅḇƀɓƃᵬᶀ"
		self.alphalower += "ćĉčċçḉȼƈɕ"
		self.alphalower += "ďḋḑḍḓḏđɖɗƌᵭᶁᶑȡ∂"
		self.alphalower += "ḟƒᵮᶂ"
		self.alphalower += "ǵğĝǧġģḡǥɠᶃ"
		self.alphalower += "ĥȟḧḣḩḥḫẖħⱨ"
		self.alphalower += "ĵɉǰȷʝɟʄ"
		self.alphalower += "ḱǩķḳḵƙⱪᶄꝁ"
		self.alphalower += "ĺľļḷḹḽḻłŀƚⱡɫɬᶅɭȴ"
		self.alphalower += "ḿṁṃᵯᶆɱ"
		self.alphalower += "ńǹňñṅņṇṋṉɲƞᵰᶇɳȵ"
		self.alphalower += "ṕṗᵽƥp̃ᵱᶈ"
		self.alphalower += "ɋʠ"
		self.alphalower += "ŕřṙŗȑȓṛṝṟɍɽᵲᶉɼɾᵳ"
		self.alphalower += "śṥŝšṧṡẛşṣṩșs̩ᵴᶊʂȿ"
		self.alphalower += "ťṫţṭțṱṯŧⱦƭʈẗᵵƫȶ"
		self.alphalower += "ṽṿʋᶌⱱⱴ"
		self.alphalower += "ẃẁŵẅẇẉẘⱳ"
		self.alphalower += "ẍẋᶍ"
		self.alphalower += "źẑžżẓẕƶȥⱬᵶᶎʐʑɀ"
		
		self.alphalower += "ɐɑɒẚʙↄꜿꝺȸǝəɛɘɜɞʚɤʩꝼⅎɡᵹɢʛᵷɣƣʜƕɦⱶɧɪɩᵼʞʟɮꞁƛʎɴŋɶɔɷȣɸⱷȹʀɹɺɻɿʁꝛꝝßƩƪʅʆſʇɥʮʯɯɰʊʌʍƍʒƹʓȝþƿƻƨƽƅɂʔʕʡʢʖǀǁǂǃʗʘʬʭꜳæꜵꜷꜹꜻꜽʣʥʤỻʪʫœꝏʨᵺƾʦʧꜩᵫ"
		
		self.alphaupper  = "AEIOUY"
		self.alphaupper += "ÁÀĂẮẰẴẲÂẤẦẪẨǍÅǺÄǞÃȦǠĄĀẢȀȂẠẶẬḀȺᶏɐɑ"
		self.alphaupper += "ÉÈĔÊẾỀỄỂĚËẼĖȨḜĘĒḖḔẺȄȆẸỆḘḚɆᶒⱸ"
		self.alphaupper += "ÍÌĬÎǏÏḮĨĮĪỈȈȊỊḬƗᵻᶖII"
		self.alphaupper += "ÓÒŎÔỐỒỖỔǑÖȪŐÕṌṎȬȮȰØǾǪǬŌṒṐỎȌȎƠỚỜỠỞỢỌỘƟⱺ"
		self.alphaupper += "ÚÙŬÛǓŮÜǗǛǙǕŰŨṸŲŪṺỦȔȖƯỨỪỮỬỰỤṲṶṴɄᵾᶙ"
		self.alphaupper += "ÝỲŶẙŸỸẎȲỶỴɎƳ"
		
		self.alphaupper += "BCDFGHJKLMNPQRSTVWXZ"
		self.alphaupper += "ḂḄḆɃƁƂᵬᶀ"
		self.alphaupper += "ĆĈČĊÇḈȻƇɕ"
		self.alphaupper += "ĎḊḐḌḒḎĐƉƊƋᵭᶁᶑȡ∂"
		self.alphaupper += "ḞƑᵮᶂ"
		self.alphaupper += "ǴĞĜǦĠĢḠǤƓᶃ"
		self.alphaupper += "ĤȞḦḢḨḤḪẖĦⱧ"
		self.alphaupper += "ĴɈǰȷʝɟʄ"
		self.alphaupper += "ḰǨĶḲḴƘⱩᶄꝁ"
		self.alphaupper += "ĹĽĻḶḸḼḺŁĿȽⱠⱢɬᶅɭȴ"
		self.alphaupper += "ḾṀṂᵯᶆɱ"
		self.alphaupper += "ŃǸŇÑṄŅṆṊṈƝȠᵰᶇɳȵ"
		self.alphaupper += "ṔṖⱣƤP̃ᵱᶈ"
		self.alphaupper += "Ɋʠ"
		self.alphaupper += "ŔŘṘŖȐȒṚṜṞɌⱤᵲᶉɼɾᵳ"
		self.alphaupper += "ŚṤŜŠṦṠṠŞṢṨȘS̩ᵴᶊʂȿ"
		self.alphaupper += "ŤṪŢṬȚṰṮŦȾƬƮẗᵵƫȶ"
		self.alphaupper += "ṼṾƲᶌⱱⱴ"
		self.alphaupper += "ẂẀŴẄẆẈẘⱳ"
		self.alphaupper += "ẌẊᶍ"
		self.alphaupper += "ŹẐŽŻẒẔƵȤⱫᵶᶎʐʑɀ"
		
		self.alphaupper += "ɐɑɒẚʙↃꜿꝺȸƎƏƐɘɜɞʚɤʩꝼℲɡᵹɢʛᵷƔƢʜǶɦⱵɧɪƖᵼʞʟɮꞁƛʎɴŊɶƆɷȢɸⱷȹƦɹɺɻɿʁꝛꝝßƩƪʅʆSʇɥʮʯƜɰƱɅʍƍƷƸʓȜÞǷƻƧƼƄɁʔʕʡʢʖǀǁǂǃʗʘʬʭꜳÆꜵꜷꜹꜻꜽʣʥʤỻʪʫŒꝏʨᵺƾʦʧꜩᵫ"
		
		self.alphabetic = self.alphalower + self.alphaupper
		
		self.numeric     = "0123456789"
		
		self.punctuation = "'\"()[]{}<>:,‒–—―…!.«»-‐?‚‘’„“”;/\\·"
		self.whitespace  = "\r\n \t " # return, newline, space, tab, non-breaking space
		
		self.alphanumeric = self.numeric + self.alphabetic
		
		return True

if __name__ == "__main__":
	print("\n\tThis is a Pacify core module and cannot be executed directly.")